//
// Created by Mayn on 25-7-13.
//

#ifndef BOTTOMGLWIDGET_H
#define BOTTOMGLWIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLVertexArrayObject>
#include <QOpenGLTexture>
#include <QMouseEvent>
#include <QWheelEvent>
#include <QVector2D>
#include <QVector3D>
#include <QMatrix4x4>
#include <QTimer>
#include <QTime>
#include <random>

#include "ViewState.h"

class BottomGLWidget : public QOpenGLWidget, protected QOpenGLFunctions {
    Q_OBJECT
public:
    BottomGLWidget(ViewState* viewState, QWidget* parent = nullptr)
        : QOpenGLWidget(parent), m_viewState(viewState) {
        setMouseTracking(true);

        // 设置定时器更新瀑布图
        m_updateTimer = new QTimer(this);
        connect(m_updateTimer, &QTimer::timeout, this, &BottomGLWidget::updateWaterfall);
        m_updateTimer->start(50); // 每50ms更新一次（20FPS）

        // 初始化随机数生成器
        m_rng.seed(std::random_device()());
        m_dist = std::uniform_real_distribution<float>(0.0f, 1.0f);
    }

    ~BottomGLWidget() override {
        // 清理资源
        makeCurrent();
        delete m_waterfallTexture;
        delete m_waterfallProgram;
        delete m_geometryProgram;
        doneCurrent();
    }

protected:
    void initializeGL() override {
        initializeOpenGLFunctions();
        glClearColor(0.0f, 0.0f, 0.0f, 1.0f); // 黑色背景

        // 创建瀑布图着色器程序
        m_waterfallProgram = new QOpenGLShaderProgram(this);
        m_waterfallProgram->addShaderFromSourceCode(QOpenGLShader::Vertex,
            "attribute vec2 position;\n"
            "attribute vec2 texCoord;\n"
            "varying vec2 v_texCoord;\n"
            "uniform mat4 projection;\n"
            "void main() {\n"
            "    gl_Position = projection * vec4(position, 0.0, 1.0);\n"
            "    v_texCoord = texCoord;\n"
            "}");
        m_waterfallProgram->addShaderFromSourceCode(QOpenGLShader::Fragment,
            "varying vec2 v_texCoord;\n"
            "uniform sampler2D waterfallTexture;\n"
            "uniform vec4 tintColor;\n"
            "void main() {\n"
            "    vec4 texColor = texture2D(waterfallTexture, v_texCoord);\n"
            "    gl_FragColor = vec4(texColor.r * tintColor.r, "
            "                       texColor.g * tintColor.g, "
            "                       texColor.b * tintColor.b, "
            "                       1.0);\n"
            "}");
        m_waterfallProgram->link();

        // 创建几何图形着色器程序（用于绘制指示线）
        m_geometryProgram = new QOpenGLShaderProgram(this);
        m_geometryProgram->addShaderFromSourceCode(QOpenGLShader::Vertex,
            "attribute vec2 position;\n"
            "uniform mat4 projection;\n"
            "void main() {\n"
            "    gl_Position = projection * vec4(position, 0.0, 1.0);\n"
            "}");
        m_geometryProgram->addShaderFromSourceCode(QOpenGLShader::Fragment,
            "uniform vec4 color;\n"
            "void main() {\n"
            "    gl_FragColor = color;\n"
            "}");
        m_geometryProgram->link();

        // 创建VBO
        m_vbo.create();
        m_waterfallVbo.create();

        // 初始化瀑布图纹理
        initWaterfallTexture();
    }

    void resizeGL(int w, int h) override {
        glViewport(0, 0, w, h);
        m_width = w;
        m_height = h;
        updateProjection();

        // 调整纹理大小以适应新窗口尺寸
        resizeWaterfallTexture();
    }

    void paintGL() override {
        glClear(GL_COLOR_BUFFER_BIT);

        // 绘制瀑布图
        drawWaterfall();

        // 绘制鼠标指示器
        if (!m_mousePos.isNull()) {
            drawMouseIndicators();
        }

        // 绘制固定指示器
        if (m_viewState->fixedIndicator() >= 0) {
            drawFixedIndicator();
        }
    }

    void mouseMoveEvent(QMouseEvent* event) override {
        m_mousePos = event->position();
        update();
    }

    void mousePressEvent(QMouseEvent* event) override {
        if (event->button() == Qt::LeftButton) {
            // 计算点击位置的世界坐标
            float worldX = (event->position().x() - m_width/2.0f) / m_viewState->scale() + m_viewState->offsetX();
            m_viewState->setFixedIndicator(worldX);
            update();
        }
    }

    void wheelEvent(QWheelEvent* event) override {
        QPoint numDegrees = event->angleDelta() / 8;
        if (!numDegrees.isNull()) {
            float zoomFactor = numDegrees.y() > 0 ? 1.1f : 0.9f;
            float oldScale = m_viewState->scale();
            float newScale = qBound(10.0f, oldScale * zoomFactor, 500.0f);
            m_viewState->setScale(newScale);

            QPointF mousePos = event->position();
            float worldX = (mousePos.x() - m_width/2.0f) / oldScale + m_viewState->offsetX();
            m_viewState->setOffsetX(worldX - (mousePos.x() - m_width/2.0f) / newScale);

            updateProjection();
            update();
        }
    }

private:
    void initWaterfallTexture() {
        // 删除旧纹理（如果存在）
        if (m_waterfallTexture) {
            delete m_waterfallTexture;
        }

        // 创建新纹理
        m_waterfallTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
        m_waterfallTexture->setSize(m_textureWidth, m_textureHeight);
        m_waterfallTexture->setFormat(QOpenGLTexture::RGBA8_UNorm);
        m_waterfallTexture->setMinMagFilters(QOpenGLTexture::Linear, QOpenGLTexture::Linear);
        m_waterfallTexture->setWrapMode(QOpenGLTexture::ClampToEdge);
        m_waterfallTexture->allocateStorage();

        // 初始化纹理数据（黑色）
        m_textureData.resize(m_textureWidth * m_textureHeight * 4);
        std::fill(m_textureData.begin(), m_textureData.end(), 0);
        m_waterfallTexture->setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, m_textureData.data());
    }

    void resizeWaterfallTexture() {
        // 根据窗口大小动态调整纹理尺寸
        m_textureWidth = m_width;
        m_textureHeight = m_height;

        // 限制最小纹理尺寸
        if (m_textureWidth < 256) m_textureWidth = 256;
        if (m_textureHeight < 256) m_textureHeight = 256;

        // 重新初始化纹理
        initWaterfallTexture();

        // 重置当前行索引
        m_currentRow = 0;
    }

    void updateWaterfall() {
        if (!m_waterfallTexture) return;

        makeCurrent();

        // 生成新行数据
        QVector<quint8> newRow(m_textureWidth * 4);
        for (int i = 0; i < m_textureWidth; ++i) {
            float value = m_dist(m_rng);

            // 热图颜色映射：蓝->青->绿->黄->红
            if (value < 0.25f) {
                // 蓝到青
                float t = value / 0.25f;
                newRow[i*4] = 0;                              // R
                newRow[i*4+1] = static_cast<quint8>(t * 255); // G
                newRow[i*4+2] = 255;                          // B
            } else if (value < 0.5f) {
                // 青到绿
                float t = (value - 0.25f) / 0.25f;
                newRow[i*4] = 0;                              // R
                newRow[i*4+1] = 255;                          // G
                newRow[i*4+2] = static_cast<quint8>((1-t) * 255); // B
            } else if (value < 0.75f) {
                // 绿到黄
                float t = (value - 0.5f) / 0.25f;
                newRow[i*4] = static_cast<quint8>(t * 255);   // R
                newRow[i*4+1] = 255;                          // G
                newRow[i*4+2] = 0;                            // B
            } else {
                // 黄到红
                float t = (value - 0.75f) / 0.25f;
                newRow[i*4] = 255;                            // R
                newRow[i*4+1] = static_cast<quint8>((1-t) * 255); // G
                newRow[i*4+2] = 0;                            // B
            }
            newRow[i*4+3] = 255; // Alpha
        }

        // 滚动纹理：将旧数据上移一行
        if (m_currentRow > 0) {
            // 复制纹理数据（从第1行开始到最后一行）
            memmove(m_textureData.data(),
                    m_textureData.data() + m_textureWidth * 4,
                    m_textureWidth * (m_textureHeight - 1) * 4);
        }

        // 添加新行数据到底部
        memcpy(m_textureData.data() + m_textureWidth * (m_textureHeight - 1) * 4,
               newRow.data(),
               m_textureWidth * 4);

        // 更新整个纹理
        m_waterfallTexture->bind();
        m_waterfallTexture->setData(QOpenGLTexture::RGBA, QOpenGLTexture::UInt8, m_textureData.data());
        m_waterfallTexture->release();

        // 更新当前行索引
        m_currentRow = (m_currentRow + 1) % m_textureHeight;

        // 请求重绘
        update();

        doneCurrent();
    }

    void updateProjection() {
        m_projection.setToIdentity();
        m_projection.ortho(-m_width/2.0f, m_width/2.0f,
                          -m_height/2.0f, m_height/2.0f,
                          -1.0f, 1.0f);
    }

    void drawWaterfall() {
        if (!m_waterfallProgram->bind()) return;
        if (!m_waterfallTexture) return;

        // 设置投影矩阵
        m_waterfallProgram->setUniformValue("projection", m_projection);
        m_waterfallProgram->setUniformValue("tintColor", QVector4D(1.0f, 1.0f, 1.0f, 1.0f));

        // 绑定纹理
        m_waterfallTexture->bind();
        m_waterfallProgram->setUniformValue("waterfallTexture", 0);

        // 定义顶点和纹理坐标
        float left = -m_width/2.0f;
        float right = m_width/2.0f;
        float bottom = -m_height/2.0f;
        float top = m_height/2.0f;

        struct Vertex {
            QVector2D position;
            QVector2D texCoord;
        };

        QVector<Vertex> vertices = {
            {{left, bottom}, {0.0f, 0.0f}},
            {{right, bottom}, {1.0f, 0.0f}},
            {{right, top}, {1.0f, 1.0f}},
            {{left, top}, {0.0f, 1.0f}}
        };

        // 绑定VBO并设置属性
        m_waterfallVbo.bind();
        m_waterfallVbo.allocate(vertices.constData(), vertices.size() * sizeof(Vertex));

        m_waterfallProgram->enableAttributeArray(0); // position
        m_waterfallProgram->setAttributeBuffer(0, GL_FLOAT, offsetof(Vertex, position), 2, sizeof(Vertex));

        m_waterfallProgram->enableAttributeArray(1); // texCoord
        m_waterfallProgram->setAttributeBuffer(1, GL_FLOAT, offsetof(Vertex, texCoord), 2, sizeof(Vertex));

        // 绘制全屏矩形
        glDrawArrays(GL_TRIANGLE_FAN, 0, vertices.size());

        m_waterfallVbo.release();
        m_waterfallTexture->release();
        m_waterfallProgram->release();
    }

    void drawMouseIndicators() {
        if (!m_geometryProgram->bind()) return;

        m_geometryProgram->setUniformValue("projection", m_projection);

        // 计算鼠标位置的世界坐标
        float mouseWorldX = (m_mousePos.x() - m_width/2.0f) / m_viewState->scale() + m_viewState->offsetX();

        // 计算三条垂直线位置
        float centerX = (mouseWorldX - m_viewState->offsetX()) * m_viewState->scale();
        float leftX = ((mouseWorldX - 0.5f) - m_viewState->offsetX()) * m_viewState->scale();
        float rightX = ((mouseWorldX + 0.5f) - m_viewState->offsetX()) * m_viewState->scale();

        // 绘制半透明填充区域
        drawRect(leftX, -m_height/2.0f,
                rightX - leftX, m_height,
                QVector4D(0.0f, 1.0f, 0.0f, 0.2f));

        // 绘制三条垂直线
        drawLine(leftX, -m_height/2.0f, leftX, m_height/2.0f,
                QVector4D(0.0f, 1.0f, 0.0f, 0.5f));
        drawLine(centerX, -m_height/2.0f, centerX, m_height/2.0f,
                QVector4D(0.0f, 1.0f, 0.0f, 1.0f));
        drawLine(rightX, -m_height/2.0f, rightX, m_height/2.0f,
                QVector4D(0.0f, 1.0f, 0.0f, 0.5f));

        m_geometryProgram->release();
    }

    void drawFixedIndicator() {
        if (!m_geometryProgram->bind()) return;

        m_geometryProgram->setUniformValue("projection", m_projection);

        // 计算三条垂直线位置
        float centerX = (m_viewState->fixedIndicator() - m_viewState->offsetX()) * m_viewState->scale();
        float leftX = ((m_viewState->fixedIndicator() - 0.5f) - m_viewState->offsetX()) * m_viewState->scale();
        float rightX = ((m_viewState->fixedIndicator() + 0.5f) - m_viewState->offsetX()) * m_viewState->scale();

        // 绘制半透明填充区域
        drawRect(leftX, -m_height/2.0f,
                rightX - leftX, m_height,
                QVector4D(1.0f, 0.5f, 0.0f, 0.3f)); // 橙色填充

        // 绘制三条垂直线
        drawLine(leftX, -m_height/2.0f, leftX, m_height/2.0f,
                QVector4D(1.0f, 0.5f, 0.0f, 0.7f)); // 橙色线
        drawLine(centerX, -m_height/2.0f, centerX, m_height/2.0f,
                QVector4D(1.0f, 0.5f, 0.0f, 1.0f));
        drawLine(rightX, -m_height/2.0f, rightX, m_height/2.0f,
                QVector4D(1.0f, 0.5f, 0.0f, 0.7f));

        m_geometryProgram->release();
    }

    void drawLine(float x1, float y1, float x2, float y2, const QVector4D& color) {
        QVector<QVector2D> verts = {
            QVector2D(x1, y1),
            QVector2D(x2, y2)
        };

        m_vbo.bind();
        m_vbo.allocate(verts.constData(), verts.size() * sizeof(QVector2D));

        m_geometryProgram->enableAttributeArray(0);
        m_geometryProgram->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0);
        m_geometryProgram->setUniformValue("color", color);

        glDrawArrays(GL_LINES, 0, verts.size());

        m_vbo.release();
    }

    void drawRect(float x, float y, float width, float height, const QVector4D& color) {
        QVector<QVector2D> verts = {
            QVector2D(x, y),
            QVector2D(x + width, y),
            QVector2D(x + width, y + height),
            QVector2D(x, y + height)
        };

        m_vbo.bind();
        m_vbo.allocate(verts.constData(), verts.size() * sizeof(QVector2D));

        m_geometryProgram->enableAttributeArray(0);
        m_geometryProgram->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0);
        m_geometryProgram->setUniformValue("color", color);

        glDrawArrays(GL_TRIANGLE_FAN, 0, verts.size());

        m_vbo.release();
    }

private:
    ViewState* m_viewState;
    QOpenGLShaderProgram* m_waterfallProgram = nullptr;
    QOpenGLShaderProgram* m_geometryProgram = nullptr;
    QOpenGLBuffer m_vbo{QOpenGLBuffer::VertexBuffer};
    QOpenGLBuffer m_waterfallVbo{QOpenGLBuffer::VertexBuffer};
    QMatrix4x4 m_projection;
    QPointF m_mousePos;
    int m_width = 0;
    int m_height = 0;
    QTimer* m_updateTimer;

    // 瀑布图纹理相关
    QOpenGLTexture* m_waterfallTexture = nullptr;
    int m_textureWidth = 800;
    int m_textureHeight = 600;
    QVector<quint8> m_textureData; // 纹理数据
    int m_currentRow = 0;          // 当前写入行

    // 随机数生成
    std::mt19937 m_rng;
    std::uniform_real_distribution<float> m_dist;
};


#endif //BOTTOMGLWIDGET_H
